package com.william.aggregate;

import com.google.common.collect.Lists;
import com.william.aggregate.enums.TimeGranularityEnum;
import com.william.aggregate.model.TimeSeriesData;
import com.william.aggregate.model.TimeSeriesPoint;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 时间序列数据聚合服务
 */
@Slf4j
public class TimeSeriesAggregator {

    /**
     * 按时间维度聚合数据
     * @param dataList 原始数据列表
     * @param truncateFunction 时间截断函数
     * @return 聚合后的数据列表
     */
    public List<TimeSeriesData> aggregate(
            List<TimeSeriesPoint> dataList,
            Function<LocalDateTime, LocalDateTime> truncateFunction) {
        
        // 增加入参校验
        if (dataList == null || dataList.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 使用Stream API直接转换为目标格式，避免中间变量
        return dataList.stream()
                .collect(Collectors.groupingBy(
                        data -> truncateFunction.apply(data.getTimestamp()),
                        Collectors.mapping(TimeSeriesPoint::getValue, Collectors.toList())
                ))
                .entrySet()
                .stream()
                .map(entry -> TimeSeriesData.builder()
                        .timestamp(entry.getKey())
                        .values(entry.getValue())
                        .build())
                .sorted(Comparator.comparing(TimeSeriesData::getTimestamp))
                .collect(Collectors.toList());
    }

    /**
     * 获取时间截断函数
     */
    private Function<LocalDateTime, LocalDateTime> getTruncateFunction(
            TimeGranularityEnum granularity,
            Integer customInterval) {
        
        switch (granularity) {
            case DAY:
                return time -> time.truncatedTo(ChronoUnit.DAYS);
            case WEEK:
                return time -> time.truncatedTo(ChronoUnit.DAYS)
                        .minusDays(time.getDayOfWeek().getValue() - 1);
            case MONTH:
                return time -> time.truncatedTo(ChronoUnit.DAYS)
                        .withDayOfMonth(1);
            case CUSTOM:
                if (customInterval == null || customInterval <= 0) {
                    throw new IllegalArgumentException("自定义时间间隔必须大于0");
                }
                return time -> time.truncatedTo(ChronoUnit.MINUTES)
                        .withMinute((time.getMinute() / customInterval) * customInterval);
            default:
                throw new IllegalArgumentException("不支持的时间粒度: " + granularity);
        }
    }
} 